package com.zmn.oms.dubbo.impl.callcenter;

import com.zmn.biz.abnormal.common.dio.AbnormalOperatorCountDIO;
import com.zmn.biz.abnormal.common.dro.AbnormalOperatorCountDRO;
import com.zmn.biz.abnormal.dubbo.interfaces.AbnormalListRemoteService;
import com.zmn.biz.complain.common.dro.complain.ChsComplainCountDRO;
import com.zmn.biz.complain.dubbo.interfaces.complain.ChsComplainApiListRemoteService;
import com.zmn.oms.business.interfaces.es.OrderWorkEsBService;
import com.zmn.oms.services.interfaces.orderencrypt.OrderEncryptService;
import org.apache.dubbo.config.annotation.Reference;
import org.apache.dubbo.config.annotation.Service;
import com.google.common.collect.Lists;
import com.zmn.common.constant.GlobalConsts;
import com.zmn.common.dto.ResponseDTO;
import com.zmn.common.utils.collection.CollectionUtil;
import com.zmn.common.utils.date.DateUtil;
import com.zmn.common.utils.logger.LoggerUtil;
import com.zmn.common.utils.math.MathUtil;
import com.zmn.common.utils.reflect.BeanMapper;
import com.zmn.common.utils.response.ResponseUtil;
import com.zmn.mcc.common.dto.staff.StaffDRO;
import com.zmn.mcc.dubbo.interfaces.staff.StaffListRemoteService;
import com.zmn.oms.dubbo.dto.zmn.callcenter.dio.EsOrderDIO;
import com.zmn.oms.dubbo.dto.zmn.callcenter.dro.CcOrderDRO;
import com.zmn.oms.dubbo.dto.zmn.callcenter.dro.EsOrderDRO;
import com.zmn.oms.dubbo.interfaces.callcenter.CallCenterEsOrderRemoteService;
import com.zmn.oms.dubbo.utils.DubboConsts;
import com.zmn.oms.model.entity.callcenterstat.EsOrderStat;
import com.zmn.base.oms.common.model.es.orderwork.EsOrderWork;
import com.zmn.oms.zmn.business.interfaces.callcenterstat.CallCenterEsOrderStatBService;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.RangeQueryBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.elasticsearch.core.query.FetchSourceFilter;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.SourceFilter;

import javax.annotation.Resource;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 描述:呼叫中心 es 查询统计 remote 实现
 *
 * @author wangjie
 * @date 14:43 2019/3/14
 **/
@Service(loadbalance = "roundrobin", timeout = 5000, retries = 2, version = DubboConsts.INTERFACE_VERSION, validation = "true")
public class CallCenterEsOrderRemoteServiceImpl implements CallCenterEsOrderRemoteService {

    private Logger logger = LoggerFactory.getLogger(CallCenterEsOrderRemoteServiceImpl.class);

    @Resource
    CallCenterEsOrderStatBService callCenterEsOrderStatBusinessService;

    @Reference(version = com.zmn.mcc.dubbo.dto.DubboConsts.INTERFACE_VERSION, check = false)
    StaffListRemoteService staffListRemoteService;
    @Reference(version = DubboConsts.INTERFACE_VERSION , check = false)
    ChsComplainApiListRemoteService chsComplainApiListRemoteService;
    @Reference(version = DubboConsts.INTERFACE_VERSION , check = false)
    AbnormalListRemoteService abnormalListRemoteService;
    @Autowired
    OrderWorkEsBService orderWorkEsBService;

    @Autowired
    private OrderEncryptService orderEncryptService;

    /**
     * 描述: 根据条件查询es order 数据 根据操作人分组
     *
     * @param esOrderDio 查询条件
     * @return java.util.List<com.zmn.oms.dubbo.dto.zmn.callcenter.dro.EsOrderDRO>
     * @author wangjie
     * @date 14:58 2019/3/14
     **/
    @Override
    public ResponseDTO<EsOrderDRO> findEsOrderGroupByOperatorId(EsOrderDIO esOrderDio) {

        if (Objects.isNull(esOrderDio)) {
            LoggerUtil.error(this.getClass(), "esOrderDIO不能为空");
            return ResponseUtil.responseFail("esOrderDIO不能为空");
        }
        if (Objects.isNull(esOrderDio.getStartDate())) {
            LoggerUtil.error(this.getClass(), "esOrderDIO.getStartDate()不能为空");
            return ResponseUtil.responseFail("esOrderDIO.getStartDate()不能为空");
        }
        if (Objects.isNull(esOrderDio.getEndDate())) {
            LoggerUtil.error(this.getClass(), "esOrderDIO.getEndDate()不能为空");
            return ResponseUtil.responseFail("esOrderDIO.getEndDate()不能为空");
        }

        String startDate = DateUtil.toString(esOrderDio.getStartDate(), DateUtil.FORMAT_DEFAULT);
        String endDate = DateUtil.toString(esOrderDio.getEndDate(), DateUtil.FORMAT_DEFAULT);

        try {
            List<EsOrderStat> esOrderStats = callCenterEsOrderStatBusinessService.statEsOrderGroupByOperatorId(startDate, endDate, esOrderDio.getChannelId());
            logger.info("加载es数据成功: {}", esOrderStats.size());
            if (esOrderStats.isEmpty()) {
                logger.info("加载es数据长度为0: {}", 0);
                return ResponseUtil.responseSuccess(Collections.emptyList(), "OK");
            }
            // 过滤id 大于 Integer 最大的,转换OperatorId 为 Integer 类型 并收集
            List<Integer> operatorIdList = esOrderStats.stream()
                    .filter(Objects::nonNull)
                    .filter(ff -> Objects.nonNull(ff.getOperatorId()))
                    .filter(ff -> ff.getOperatorId() < Integer.MAX_VALUE)
                    .map(EsOrderStat::getOperatorId)
                    .map(Long::intValue)
                    .collect(Collectors.toList());
            logger.info("转换operatorIdList 成功,条数: {}", operatorIdList.size());
            // 投诉的map
            Map<Integer, Integer> trackMap = this.getTrack(operatorIdList, startDate, endDate);
            // 员工得map
            Map<Integer, String> staffMap = this.getStaffMap(operatorIdList);
            // 异常的map
            Map<Integer, Integer> exceptionMap = this.getExceptionMap(operatorIdList, startDate, endDate);

            List<EsOrderDRO> collect = esOrderStats.stream()
                    .filter(ff -> Objects.nonNull(ff.getOperatorId()))
                    .map(mm -> {
                        EsOrderDRO esOrderDRO = new EsOrderDRO();
                        esOrderDRO.setOrderCount(mm.getOrderCount());
                        esOrderDRO.setCallBackCount(mm.getCallBackCount());
                        esOrderDRO.setExceptionCount(mm.getExceptionCount());
                        esOrderDRO.setVisitCount(mm.getVisitCount());
                        esOrderDRO.setComplaintCount(trackMap.get(mm.getOperatorId().intValue()));
                        esOrderDRO.setRecommendCount(mm.getRecommendCount());
                        esOrderDRO.setRepairCount(mm.getRepairCount());
                        if (mm.getOperatorId() > Integer.MAX_VALUE) {
                            mm.setOperatorId(0L);
                        }
                        esOrderDRO.setOperatorId(mm.getOperatorId());
                        esOrderDRO.setOperatorName(staffMap.get(mm.getOperatorId().intValue()));
                        //成功率 version 2.0.1 添加
                        esOrderDRO.setSuccessfulOrderCount(mm.getSuccessfulOrderCount());
                        //计算成功率 公式为 成功单/新单
                        esOrderDRO.setSuccessfulRate(this.div(mm.getSuccessfulOrderCount(), mm.getOrderCount()));
                        //异常数量
                        esOrderDRO.setExceptionCount(exceptionMap.get(mm.getOperatorId().intValue()));
                        return esOrderDRO;
                    }).collect(Collectors.toList());

            return ResponseUtil.responseSuccess(collect, "OK");
        } catch (Exception e) {
            logger.error("获取数据失败,程序异常", e);
            return ResponseUtil.responseFail("获取数据失败!");
        }
    }

    /**
     * 按电话查询订单
     * @param phone
     * @return
     */
    @Override
    public com.zmn.common.dto2.ResponseDTO<List<CcOrderDRO>> listOrderByPhone(String phone) {
        logger.info("CallCenterEsOrderRemoteServiceImpl#listOrderByPhone入参phone[{}]", phone);

        // 电话查询
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery()
                .filter(QueryBuilders.termQuery("contact.phone", orderEncryptService.encrypt(phone)));
        NativeSearchQuery searchQuery = new NativeSearchQuery(queryBuilder);
        searchQuery.setPageable(PageRequest.of(0, 100, Sort.by(Sort.Order.asc("receiveTime"))));
        String[] columns = {"id", "orderId", "contact", "platWork", "status", "resultStatus", "warrantyProductMaxExpiredTime","completeTime"};
        SourceFilter sourceFilter = new FetchSourceFilter(columns, null);
        searchQuery.addSourceFilter(sourceFilter);
        logger.debug("电话查询[{}]", searchQuery.getQuery().toString());
        List<EsOrderWork> esOrderWorks = orderWorkEsBService.listPageByQuery(searchQuery);
        if (CollectionUtil.isNullOrEmpty(esOrderWorks)) {
            return com.zmn.common.dto2.ResponseDTO.success(Collections.emptyList());
        }
        // Bean转换并计算是否在保修期内
        List<CcOrderDRO> list = Lists.newArrayList();
        for (EsOrderWork esOrderWork : esOrderWorks) {
            CcOrderDRO orderDRO = BeanMapper.map(esOrderWork, CcOrderDRO.class);
            orderDRO.setWorkId(esOrderWork.getId());
            orderDRO.setWarrantyStatus(GlobalConsts.NONE);
            orderDRO.setPhone(phone);
            orderDRO.setWarrantyStatus(esOrderWork.getWarrantyProductMaxExpiredTime() != null && DateUtil.getNow().compareTo(esOrderWork.getWarrantyProductMaxExpiredTime()) != 1 ?
                    GlobalConsts.YES : GlobalConsts.NO);
            list.add(orderDRO);
        }

        logger.info("按电话查询订单返回==>{}", list);
        return com.zmn.common.dto2.ResponseDTO.success(list);
    }

    /**
     * 按时间查询过保订单
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @return
     */
    @Override
    public com.zmn.common.dto2.ResponseDTO<List<CcOrderDRO>> listExpiredWarrantyOrder(Date startTime, Date endTime) {
        logger.info("CallCenterEsOrderRemoteServiceImpl#listExpiredWarrantyOrder入参startTime[{}]endTime[{}]", startTime, endTime);

        BoolQueryBuilder builder = QueryBuilders.boolQuery();
        RangeQueryBuilder queryBuilder = QueryBuilders.rangeQuery("warrantyProductMaxExpiredTime");
        queryBuilder.gte(DateUtil.dateFormatToString(startTime, DateUtil.FORMAT_DEFAULT));
        queryBuilder.lte(DateUtil.dateFormatToString(endTime, DateUtil.FORMAT_DEFAULT));
        builder.must(queryBuilder);
        NativeSearchQuery searchQuery = new NativeSearchQuery(builder);
        searchQuery.setPageable(PageRequest.of(0, 3000, Sort.by(Sort.Order.asc("receiveTime"))));
        String[] columns = {"id", "orderId", "contact", "platWork", " status", "resultStatus", "warrantyProductMaxExpiredTime"};
        logger.debug("过期时间查询[{}]", searchQuery.getQuery().toString());
        List<EsOrderWork> esOrderWorks = orderWorkEsBService.listPageByQuery(searchQuery);
        if (CollectionUtil.isNullOrEmpty(esOrderWorks)) {
            return com.zmn.common.dto2.ResponseDTO.success(Collections.emptyList());
        }

        List<CcOrderDRO> list = Lists.newArrayList();
        for (EsOrderWork esOrderWork : esOrderWorks) {
            CcOrderDRO orderDRO = BeanMapper.map(esOrderWork, CcOrderDRO.class);
            if (esOrderWork.getContact() != null) {
                orderDRO.setPhone(esOrderWork.getContact().getPhone()[0]);
            }
            list.add(orderDRO);
        }
        logger.info("过期时间查询订单返回==>{}", list);
        return com.zmn.common.dto2.ResponseDTO.success(list);
    }

    /**
     * 描述: 获取投诉数据 转换为map
     *
     * @param operatorIdList 操作人id 集合
     * @param startDate      开始时间
     * @param endDate        结束时间
     * @author wangjie
     * @date 15:27 2019/4/1
     **/
    private Map<Integer, Integer> getTrack(List<Integer> operatorIdList, String startDate, String endDate) {

        com.zmn.common.dto2.ResponseDTO<List<ChsComplainCountDRO>> trackDTO = chsComplainApiListRemoteService.listCountCreateNumByQuery(operatorIdList, startDate, endDate);
        if (!trackDTO.isSuccess()) {
            LoggerUtil.error(this.getClass(), "调用远程服务异常");
            return Collections.emptyMap();
        }
        return Optional.ofNullable(trackDTO.getData()).orElse(Collections.emptyList()).stream()
                .filter(trackComplainCountDRO -> Objects.nonNull(trackComplainCountDRO.getStaffId()))
                .collect(Collectors.toMap(ChsComplainCountDRO::getStaffId, ChsComplainCountDRO::getCountNum));
    }

    /**
     * 描述: 获取员工数据 转换为map
     *
     * @param operatorIdList 操作人id 集合
     * @return java.util.Map<java.lang.Integer, java.lang.String>
     * @author wangjie
     * @date 15:36 2019/4/1
     **/
    private Map<Integer, String> getStaffMap(List<Integer> operatorIdList) {

        com.zmn.common.dto2.ResponseDTO<List<StaffDRO>> staffResult = staffListRemoteService.listStaffByStaffIds(operatorIdList, null);

        if (!staffResult.isSuccess()) {
            LoggerUtil.error(this.getClass(), "调用远程服务异常");
            return Collections.emptyMap();
        }
        return Optional.ofNullable(staffResult.getData()).orElse(Collections.emptyList()).stream()
                .filter(staffDRO -> Objects.nonNull(staffDRO.getStaffId()))
                .collect(Collectors.toMap(StaffDRO::getStaffId, StaffDRO::getStaffName));
    }

    /**
     * 描述:获取异常数据 转换为map
     *
     * @param operatorIdList 操作人id 集合
     * @param startDate      开始时间
     * @param endDate        结束时间
     * @return java.util.Map<java.lang.Integer, java.lang.String>
     * @author wangjie
     * @date 15:41 2019/4/1
     **/
    private Map<Integer, Integer> getExceptionMap(List<Integer> operatorIdList, String startDate, String endDate) throws ParseException {
        SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd");
        AbnormalOperatorCountDIO abnormalOperatorCountDIO = AbnormalOperatorCountDIO.builder()
                .startTime(sf.parse(startDate)).endTime(sf.parse(endDate)).operatorIdList(operatorIdList).build();
        com.zmn.common.dto2.ResponseDTO<List<AbnormalOperatorCountDRO>> numByCreater = abnormalListRemoteService.countAbnormalByQuery(abnormalOperatorCountDIO);
        if (!numByCreater.isSuccess()) {
            LoggerUtil.error(this.getClass(), "调用远程服务异常");
            return Collections.emptyMap();
        }
        return Optional.ofNullable(numByCreater.getData()).orElse(Collections.emptyList()).stream()
                .filter(abnormalCountDRO -> Objects.nonNull(abnormalCountDRO.getOperatorId()))
                .collect(Collectors.toMap(AbnormalOperatorCountDRO::getOperatorId, AbnormalOperatorCountDRO::getCount));
    }

    /**
     * 描述: 除法计算 判断null 与 0
     *
     * @param divisor  除数
     * @param dividend 被除数
     * @return java.lang.Double
     * @author wangjie
     * @date 16:00 2019/4/1
     **/
    private Double div(Integer divisor, Integer dividend) {

        if (Objects.isNull(dividend)) {
            return 0.00;
        }
        if (Objects.equals(dividend, GlobalConsts.NONE)) {
            return 0.00;
        }
        if (Objects.isNull(divisor)) {
            divisor = 0;
        }
        return MathUtil.div(divisor, dividend, 2);
    }

}
